package com.cw.lang.common.mapper.utils;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;

import javax.sql.DataSource;

import org.apache.commons.lang3.StringUtils;

import com.cw.lang.common.enums.EnumDialect;
import com.cw.lang.common.enums.EnumMybatisError;
import com.cw.lang.common.exception.MybatisException;

/**
 * 根据url获取数据库方言
 *
 * @author shenly@yunrong.cn
 * @version V2.1
 * @since 2.1.0 2019/4/19 14:36
 */
public class DialectUtils {

    private static Map<String, EnumDialect> dialectMap = new ConcurrentHashMap<>(4);

    private static ReentrantLock lock = new ReentrantLock();

    /**
     * 获取数据库方言
     *
     * @param dataSource 数据源
     * @return 数据库方言
     */
    public static EnumDialect getDialect(DataSource dataSource) {

        String url = getUrl(dataSource);

        if (dialectMap.containsKey(url)) {
            return dialectMap.get(url);
        }
        try {
            lock.lock();
            if (dialectMap.containsKey(url)) {
                return dialectMap.get(url);
            }

            if (StringUtils.isBlank(url)) {
                throw new MybatisException(EnumMybatisError.DATABASE_URL_NOT_EXISTS.getCode(),
                    EnumMybatisError.DATABASE_URL_NOT_EXISTS.getDescription());
            }

            EnumDialect dialect = EnumDialect.fromJdbcUrl(url);
            if (dialect == null) {
                throw new MybatisException(EnumMybatisError.DIALECT_NOT_EXISTS.getCode(),
                    EnumMybatisError.DIALECT_NOT_EXISTS.getDescription());
            }
            dialectMap.put(url, dialect);
            return dialect;
        } finally {
            lock.unlock();
        }
    }

    /**
     * 获取数据库连接url
     *
     * @param dataSource 数据源
     * @return 数据库连接url
     */
    private static String getUrl(DataSource dataSource) {
        try (Connection conn = dataSource.getConnection()) {
            return conn.getMetaData()
                .getURL();
        } catch (SQLException e) {
            throw new MybatisException(EnumMybatisError.GET_URL_ERROR.getCode(),
                EnumMybatisError.GET_URL_ERROR.getDescription(), e);
        }
    }
}
